﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using Org.BouncyCastle.Asn1;

namespace TheClerk.Forms.Templates.raw.Envelope
{
    #region internal StrongBox
    // Serialize() complete
    /// <summary>
    /// Array of StrongBoxItem
    /// </summary>
    /// <remarks>
    /// StrongBox ::= SEQUENCE(0..MAX) OF StrongBoxItem
    /// </remarks>
    internal class StrongBox
    {
        SortedSet<StrongBoxItem> data = new SortedSet<StrongBoxItem>();

        public ICollection Collection { get { return data; } }

        internal void Add(StrongBoxItem strongBoxItem)
        {
            this.data.Add(strongBoxItem);
        }
        internal void SetSymKey(byte[] keyTBProtected)
        {
            this.SymKey = keyTBProtected; 
        }

        /// <summary>
        /// created by OpaquePayload and passed in
        /// </summary>
        public byte[] SymKey { internal get; set; }

        /// <summary>
        /// created by Envelope and passed in 
        /// </summary>
        public Chop OuterChop { internal get; set; }

        public Stream Serialize()
        {
            var stream = new MemoryStream();
            if ((data.Count == 0) && (SymKey != null))
                throw new InvalidOperationException("have recipients but no symkey");
            if (SymKey == null)
            {
                // If SymKey is null, then we're in a context where there are no recipients
                // Should return NULL for it, so we return DerNull.Instance.
                stream.Write(DerNull.Instance.GetDerEncoded(),0,DerNull.Instance.GetDerEncoded().Length);
                stream.Seek(0, System.IO.SeekOrigin.Begin);
                return stream;
            }

            var sg = new Org.BouncyCastle.Asn1.DerSequenceGenerator(stream);
            foreach (StrongBoxItem sbi in data)
            {
                sbi.SetSymmetricKey(this.SymKey);
                sbi.SetOuterChop(this.OuterChop);
                sg.AddObject(sbi.toAsn1Encodable());
            }
            sg.Close();
            stream.Seek(0, SeekOrigin.Begin);
            return stream;
        }

        public Asn1Encodable ToAsn1Encodable()
        {
            return Asn1Object.FromStream(Serialize());
        }
    }
    #endregion
}
